﻿/* --------------------------------------------------------------
 * exMath (C) Laurens Ruijtenberg
 * 
 * This code is being distributed under the MS-PL license. Feel
 * free to contact me if you like this code.
 * -------------------------------------------------------------- */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace exMath.Common
{
    public class RationalNumber
    {
        private int _numerator;
        private int _denominator;

        public static RationalNumber MaxValue
        {
            get
            {
                return new RationalNumber(int.MaxValue, int.MaxValue);
            }
        }

        public static RationalNumber MinValue
        {
            get
            {
                return new RationalNumber(int.MinValue, int.MinValue);
            }
        }

        public int Numerator 
        {
            get
            {
                return _numerator;
            }

            set
            {
                _numerator = value;
            }
        }
        
        public int Denominator 
        {
            get
            {
                return _denominator;
            }

            set
            {
                if (value > 0.0)
                {
                    _denominator = value;
                }
                else
                {
                    throw new InvalidOperationException("Denominator cannot be 0.");
                }
            }
        }

        /// <summary>
        /// Represents the real representation (R) of this rational number (Q).
        /// </summary>
        public double RealValue
        {
            get
            {
                return (double)_numerator / (double)_denominator;
            }
        }

        public RationalNumber()
        {
            _numerator = 1;
            _denominator = 1;
        }

        public RationalNumber(int Numerator, int Denominator)
        {
            _numerator = Numerator;
            _denominator = Denominator;
        }

        public RationalNumber(double RealNumber, int DenominatorBase)
        {
            //todo: finish
            double IntegerPart = Math.Truncate(RealNumber);
            double DecimalPart = RealNumber - IntegerPart;
        }

        public static bool operator !=(RationalNumber r1, RationalNumber r2)
        {
            return !(r1 == r2);
        }

        public static bool operator !=(RationalNumber r1, double r2)
        {
            return !(r1 == r2);
        }

        public static bool operator ==(RationalNumber r1, RationalNumber r2)
        {
            return (r1.Numerator * r2.Denominator) == (r1.Denominator * r2.Numerator);
        }

        public static bool operator ==(RationalNumber r1, double r2)
        {
            return (r1.RealValue == r2);
        }

        public static bool operator >(RationalNumber r1, RationalNumber r2)
        {
            return r1.RealValue > r2.RealValue;
        }

        public static bool operator <(RationalNumber r1, RationalNumber r2)
        {
            return r1.RealValue < r2.RealValue;
        }

        public static bool operator <=(RationalNumber r1, RationalNumber r2)
        {
            return r1.RealValue <= r2.RealValue;
        }

        public static bool operator >=(RationalNumber r1, RationalNumber r2)
        {
            return r1.RealValue >= r2.RealValue;
        }

        public static RationalNumber operator +(RationalNumber r1, RationalNumber r2)
        {
            return new RationalNumber()
            {
                Numerator = (r1.Numerator * r2.Denominator) + (r1.Denominator * r2.Numerator),
                Denominator = r1.Denominator * r2.Denominator
            };
        }

        public static RationalNumber operator -(RationalNumber r1, RationalNumber r2)
        {
            return new RationalNumber()
            {
                Numerator = (r1.Numerator * r2.Denominator) - (r1.Denominator * r2.Numerator),
                Denominator = r1.Denominator * r2.Denominator
            };
        }

        public static RationalNumber operator *(RationalNumber r1, RationalNumber r2)
        {
            return new RationalNumber()
            {
                Numerator = r1.Numerator * r2.Numerator,
                Denominator = r1.Denominator * r2.Denominator
            };
        }

        public static RationalNumber operator *(RationalNumber r1, int r2)
        {
            return new RationalNumber()
            {
                Numerator = r1.Numerator * r2,
                Denominator = r1.Denominator
            };
        }

        public static RationalNumber operator /(RationalNumber r1, RationalNumber r2)
        {
            return new RationalNumber()
            {
                Numerator = r1.Numerator * r2.Denominator,
                Denominator = r1.Denominator * r2.Numerator
            };
        }

        public RationalNumber Simplify()
        {
            int gcd = MathUtilities.GreatesCommonDevider(this._numerator, this._denominator);
            return new RationalNumber((this.Numerator / gcd), (this.Denominator / gcd));
        }

        public override bool Equals(object obj)
        {
            if (obj is RationalNumber)
            {
                return ((RationalNumber)obj) == this;
            }
            else
            {
                return false;
            }
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return this.RealValue.ToString();
        }
    }
}
